const WebSocket = require('ws');
const { fileToRequest } = require('../../utils');
const { srcImportMap } = require('./serverPluginVue');

const latestVersionsMap = new Map();

function hmrPlugin(context) {
  const { app, server, watcher } = context;

  app.use((ctx, next) => {
    if (ctx.query.t) {
      latestVersionsMap.set(ctx.path, ctx.query.t)
    }
    return next()
  })

  const wss = new WebSocket.Server({ noServer: true });

  server.on('upgrade', (req, socket, head) => {
    if (req.headers['sec-websocket-protocol'] === 'vite-hmr') {
      wss.handleUpgrade(req, socket, head, (ws) => {
        wss.emit('connection', ws, req)
      })
    }
  })

  wss.on('connection', (socket) => {
    socket.send(JSON.stringify({ type: 'connected' }))
  })

  const send = (watcher.send = (payload) => {
    const stringified = JSON.stringify(payload, null, 2)
    console.log(`update: ${stringified}`)

    wss.clients.forEach((client) => {
      if (client.readyState === WebSocket.OPEN) {
        client.send(stringified)
      }
    })
  })

  const handleJSReload = (watcher.handleJSReload = (
    filePath,
    timestamp = Date.now()
  ) => {

    const publicPath = fileToRequest(filePath);

    const path = srcImportMap.get(publicPath);

    if (publicPath.endsWith('js') && !path) {
      send({
        type: 'full-reload',
        path: publicPath
      })
      console.log(`[vite] ` + `page reloaded.`)
    } else {
      send({
        type: path.endsWith('vue') ? 'vue-reload' : 'js-update',
        path: path,
        changeSrcPath: publicPath,
        timestamp
      })
    }
  })

  watcher.on('change', (file) => {
    if (!(file.endsWith('.vue') || file.endsWith('.css'))) {
      handleJSReload(file)
    }
  })
}

module.exports = hmrPlugin;